import userEvent from "@testing-library/user-event";
import { useState } from "react";

import { fireEvent, render, screen } from "__support__/ui";

import { TextWidget } from "./TextWidget";

const TextInputWithStateWrapper = ({
  value,
  onChange,
  focusChanged,
}: {
  value?: number | string;
  onChange?: (value: string | number | null) => void;
  focusChanged?: (focused: boolean) => void;
}) => {
  const [val, setVal] = useState<number | string | null>(value ?? "");
  return (
    <TextWidget
      value={val ?? ""}
      setValue={(value) => {
        setVal(value);
        onChange?.(value);
      }}
      focusChanged={focusChanged ?? jest.fn()}
    />
  );
};

describe("TextWidget", () => {
  it("should render correctly", () => {
    render(
      <TextWidget
        value={"Hello, world!"}
        setValue={jest.fn()}
        focusChanged={jest.fn()}
      ></TextWidget>,
    );
    expect(screen.getByRole("textbox")).toHaveValue("Hello, world!");
  });

  it("should accept editing", () => {
    render(
      <TextWidget
        value={""}
        setValue={jest.fn()}
        focusChanged={jest.fn()}
      ></TextWidget>,
    );

    fireEvent.change(screen.getByRole("textbox"), {
      target: { value: "Toucan McBird" },
    });
    expect(screen.getByRole("textbox")).toHaveValue("Toucan McBird");
  });

  it("should render a zero as an initial value", () => {
    render(
      <TextWidget value={0} setValue={jest.fn()} focusChanged={jest.fn()} />,
    );

    expect(screen.getByRole("textbox")).toHaveValue("0");
  });

  it("should accept zero as an input value", async () => {
    render(<TextInputWithStateWrapper />);

    const textbox = screen.getByRole("textbox");

    await userEvent.type(textbox, "0");
    expect(textbox).toHaveValue("0");
  });

  it("should keep zero value when pressing enter", async () => {
    render(<TextInputWithStateWrapper />);

    const textbox = screen.getByRole("textbox");

    await userEvent.type(textbox, "0{enter}");
    expect(textbox).toHaveValue("0");
  });

  it("should not call setValue twice when pressing enter", async () => {
    const onChangeSpy = jest.fn();

    render(<TextInputWithStateWrapper onChange={onChangeSpy} />);

    const textbox = screen.getByRole("textbox");

    await userEvent.type(textbox, "0{enter}");

    expect(onChangeSpy).toHaveBeenCalledTimes(1);
  });

  it("should not call handlers when pressing `esc`", async () => {
    const onChangeSpy = jest.fn();
    const focusChangedSpy = jest.fn();

    render(
      <TextInputWithStateWrapper
        onChange={onChangeSpy}
        focusChanged={focusChangedSpy}
      />,
    );

    const textbox = screen.getByRole("textbox");

    await userEvent.type(textbox, "Foo{esc}");

    expect(onChangeSpy).toHaveBeenCalledTimes(0);
    expect(focusChangedSpy).not.toHaveBeenCalledWith(false);
  });
});
